﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MarsRover
{
    class MarsControl
    {
        private const string COMMANDS = "LRM";

        public ISurface CreateSurface(string input)
        {
            if(input == null)
            {
                throw new ArgumentNullException("input must not be null");
            }

            string[] split = input.Split(' ');
            if(split.Length != 2)
            {
                throw new ArgumentException("input requres 2 numbers separated by space");
            }

            int width;
            int height;

            if(!Int32.TryParse(split[0], out width))
            {
                throw new ArgumentException("not a number");
            }

            if(!Int32.TryParse(split[1], out height))
            {
                throw new ArgumentException("not a number");
            }

            return new Surface(width, height);
        }

        public int AddRover(ISurface surface, string input)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input must not be null");
            }

            if (surface == null)
            {
                throw new ArgumentNullException("surface must not be null");
            }

            string[] split = input.Split(' ');
            if (split.Length != 3)
            {
                throw new ArgumentException("input requres 2 numbers and 1 character separated by space");
            }

            int x;
            int y;
            Heading heading;

            if (!Int32.TryParse(split[0], out x))
            {
                throw new ArgumentException("not a number");
            }

            if (!Int32.TryParse(split[1], out y))
            {
                throw new ArgumentException("not a number");
            }

            if (!Enum.TryParse<Heading>(split[2], out heading))
            {
                throw new ArgumentException("not a valid heading");
            }

            return surface.AddRover(x, y, heading);
        }

        public string ExecuteCommand(ISurface surface, int roverId, string input)
        {
            if (surface == null)
            {
                throw new ArgumentNullException("surface must not be null");
            }

            if (input == null)
            {
                throw new ArgumentNullException("input must not be null");
            }

            if (input == string.Empty)
            {
                throw new ArgumentOutOfRangeException("input must not be empty");
            }

            IRover rover = surface.GetRover(roverId);

            if (rover == null)
            {
                throw new ArgumentOutOfRangeException("Unknown rover id");
            }

            foreach (var c in input)
            {
                if (!COMMANDS.Contains(c))
                {
                    throw new ArgumentOutOfRangeException(string.Format("Invalid command character {0}", c));
                }

                if(c == 'M')
                {
                    if (!surface.IsRoverAbleToMove(rover))
                    {
                        throw new RoverException("Unable to move");
                    }

                    rover.Move();
                }

                if (c == 'R')
                {
                    rover.RotateRight();
                }

                if (c == 'L')
                {
                    rover.RotateLeft();
                }
            }

            return string.Format("{0} {1} {2}", rover.Position.X, rover.Position.Y, rover.Heading);
        }

        public string GetRoverCoordinates(ISurface surface, int roverId)
        {
            IRover rover = surface.GetRover(roverId);

            if (rover == null)
            {
                throw new ArgumentOutOfRangeException("Unknown rover id");
            }

            return string.Format("{0} {1} {2}", rover.Position.X, rover.Position.Y, rover.Heading);
        }
    }
}
